package com.avalon.shop.service;

import com.avalon.core.condition.Condition;
import com.avalon.core.context.Context;
import com.avalon.core.enums.ServiceOperateEnum;
import com.avalon.core.exception.AvalonException;
import com.avalon.core.model.RecordRow;
import com.avalon.core.util.*;
import com.avalon.shop.ShopContext;
import com.avalon.shop.config.ShopConfig;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class UserService extends BaseService {
    public UserService(ShopConfig shopConfig, ShopContext shopContext) {
        super(shopConfig, shopContext);
    }

    public void updateUserPhone(Integer userId, String purePhoneNumber, String countryCode) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", userId);
        param.put("phone", purePhoneNumber);
        param.put("countryCode", countryCode);
        updateModel(param);
    }

    /**
     * 创建pet用户，通过微信小程序创建
     *
     * @param openId
     * @return userId
     */
    public Integer getOrCreatePetUser(String openId) {
        log.info("getOrCreatePetUser: openId={}", openId);
        HashMap<String, Object> param = new HashMap<>();
        param.put("openId", openId);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        headers.put("token", shopContext.getBackToken());
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer() + "/pet/get/user",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            RecordRow recordRow = JacksonUtil.convert2Map(responseEntity.getBody());
            if (recordRow.isEmpty()) {
                throw new AvalonException("用户不存在/创建失败");
            }
            return recordRow.getInteger("id");
        }
        throw new AvalonException("用户不存在/创建失败");
    }

    public void addUserPet(String petName,
                           Integer userId,
                           Integer petCategoryId,
                           Integer petSmallTypeId,
                           String sex,
                           String avatar,
                           String birthday) {
        log.info("addUserPet: petName={}, userId={}, petCategoryId={}, petSmallTypeId={},sex={},avatar={},birthday={}",
                petName, userId, petCategoryId, petSmallTypeId, sex, avatar, birthday);

        addModel("pet.user.pet", new HashMap<String, Object>() {
            {
                put("name", petName);
                put("petUserId", userId);
                put("petCategoryId", petCategoryId);
                put("petSmallTypeId", petSmallTypeId);
                put("sex", sex);
                put("avatar", avatar);
                put("birthday", birthday);
            }
        });
    }

    public void updateUserPet(Integer id,
                              String petName,
                              Integer userId,
                              Integer petCategoryId,
                              Integer petSmallTypeId,
                              String sex,
                              String avatar,
                              String birthday) {
        log.info("addUserPet: id={},petName={}, userId={}, petCategoryId={}, " +
                        "petSmallTypeId={},sex={},avatar={},birthday={}",
                id, petName, userId, petCategoryId,
                petSmallTypeId, sex, avatar, birthday);

        updateModel("pet.user.pet", new HashMap<String, Object>() {
            {
                put("id", id);
                put("name", petName);
                put("petUserId", userId);
                put("petCategoryId", petCategoryId);
                put("petSmallTypeId", petSmallTypeId);
                put("sex", sex);
                put("avatar", avatar);
                put("birthday", birthday);
            }
        });
    }

    public List<Map> getUserPets(Integer userId, String state) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        if (StringUtils.isNotEmpty(state)) {
            param.put("state", state);
        }

        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("token", shopContext.getBackToken());
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer() + "/pet/get/user/pets",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            List<Map> maps = JacksonUtil.convert2Object(responseEntity.getBody(), new TypeReference<List<Map>>() {
            });
            return maps;
        } else {
            log.error("getPetCategory 错误:" + responseEntity.getBody());
            throw new AvalonException(responseEntity.getBody());
        }
    }

    @Override
    protected String getServiceName() {
        return "pet.user";
    }

    public Map getUserThingCount(Integer userId) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("token", shopContext.getBackToken());
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer() + "/pet/get/user/thing/count",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            Map maps = JacksonUtil.convert2Object(responseEntity.getBody(), new TypeReference<Map>() {
            });
            return maps;
        } else {
            log.error("getPetCategory 错误:" + responseEntity.getBody());
            throw new AvalonException(responseEntity.getBody());
        }
    }

    public void addFollow(Integer userId, Integer followId) {
        log.info("addFollow userId:{},followId:{}",
                userId, followId);
        HashMap<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("followId", followId);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("token", shopContext.getBackToken());
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer()
                        + "/pet/add/user/follow",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {

        } else {
            log.error("addFollow 错误:" + responseEntity.getBody());
            throw new AvalonException(responseEntity.getBody());
        }
    }

    public void deleteFollow(Integer userId, Integer followId) {
        log.info("deleteFollow userId:{},followId:{}",
                userId, followId);
        HashMap<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("followId", followId);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("token", shopContext.getBackToken());
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer()
                        + "/pet/delete/user/follow",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {

        } else {
            log.error("deleteFollow 错误:" + responseEntity.getBody());
            throw new AvalonException(responseEntity.getBody());
        }
    }

    public Map getUserDetail(Integer userId) {
        return getModelDetail("id,nickName,sex,avatar,uid,imId,phone", userId);
    }

    public Map getUserDetailByImId(Integer imId) {
        return getModelDetail(getServiceName(), "id,nickName,sex,avatar,uid,imId",
                "(=,imId," + imId + ")");
    }

    public void updateUserDetail(Integer userId, String avatar, String nickName) {
        log.info("updateUserDetail userId:{},avatar:{},nickName:{}",
                userId, avatar, nickName);
        Map param = new HashMap<String, Object>();
        param.put("id", userId);
        if (ObjectUtils.isNotEmpty(avatar)) {
            param.put("avatar", avatar);
        }
        if (ObjectUtils.isNotEmpty(nickName)) {
            param.put("nickName", nickName);
        }
        updateModel("pet.user", param);
    }


    public Map getUserFollow(Integer userId, Integer followId) {
        return getModelDetail("pet.follow",
                "id",
                "(&,(=,userId," + userId + "),(=,followId," + followId + "))");
    }


    /**
     * 添加用户提醒
     *
     * @param remind
     * @param date
     * @param time
     * @param often
     * @param userId
     * @param petIds
     * @return
     */
    public RecordRow addUserRemind(String remind,
                                   String date,
                                   String time,
                                   String often,
                                   Integer userId,
                                   List<Integer> petIds) {
        log.info("addUserRemind remind:{},date:{},time:{},often:{},userId:{},petIds:{}",
                remind, date, time, often, userId, petIds);
        Map param = new HashMap<String, Object>();
        param.put("name", remind);
        param.put("remindDate", date);
        param.put("remindTime", time);
        param.put("often", often);
        param.put("userId", userId);
        if (ObjectUtils.isNotEmpty(petIds)) {
            List<Map> petIdList = new ArrayList<>();
            for (Integer petId : petIds) {
                petIdList.add(new HashMap<String, Object>() {{
                    put("petUserPetId", petId);
                }});
            }
            param.put("petIds", petIdList);
        }
        return addModel("pet.remind", param);
    }

    /**
     * 删除提醒
     *
     * @param id
     */
    public void deleteUserRemind(Integer id) {
        deleteModel("pet.remind", id);
    }

    public void updateUserRemind(Integer id,
                                 String remind,
                                 String date,
                                 String time,
                                 String often,
                                 List<Integer> petIds) {
        log.info("updateUserRemind id:{},remind:{},date:{},time:{},often:{}",
                id, remind, date, time, often);
        Map param = new HashMap<String, Object>();
        param.put("id", id);
        param.put("remind", remind);
        param.put("remindDate", date);
        param.put("remindTime", time);
        param.put("often", often);
        if (ObjectUtils.isNotEmpty(petIds)) {
            List<Map> petIdList = new ArrayList<>();
            for (Integer petId : petIds) {
                petIdList.add(new HashMap<String, Object>() {{
                    put("petUserPetId", petId);
                    put("op", ServiceOperateEnum.insert.toString());
                }});
            }
            param.put("petIds", petIdList);
        }
        updateModel("pet.remind", param);
    }

    public Map getRemindDetail(Integer id) {
        return getModelDetail("pet.remind",
                "id,name,remindDate," +
                        "remindTime,often,done," +
                        "petIds.petUserPetId.avatar,petIds.petUserPetId.id",
                id);
    }

    public List<Map> getRemindList(Integer userId, Integer pageNum, Integer pageSize) {
        return getModelPage("pet.remind",
                "id,name,remindDate," +
                        "remindTime,often,done," +
                        "petIds.petUserPetId.avatar,petIds.petUserPetId.id",
                pageNum,
                pageSize,
                "(&,(=,userId," + userId + "),(=,done,false))",
                "remindDate desc,remindTime desc");
    }

    public void doneUserRemind(Integer id) {
        log.info("doneUserRemind id:{}", id);
        updateModel("pet.remind", new HashMap<>() {{
            put("id", id);
            put("done", true);
        }});
    }

    public RecordRow addUserAccount(String name,
                                    BigDecimal account,
                                    String accountDate,
                                    String remark,
                                    Integer userId,
                                    List<Integer> petIds) {
        log.info("addUserAccount name:{},account:{},accountDate:{},remark:{},userId:{},petIds:{}",
                name, account, accountDate, remark, userId, petIds);
        Map param = new HashMap<String, Object>();
        param.put("name", name);
        param.put("amount", account);
        param.put("accountDate", accountDate);
        param.put("remark", remark);
        param.put("userId", userId);

        if (ObjectUtils.isNotEmpty(petIds)) {
            List<Map> petIdList = new ArrayList<>();
            for (Integer petId : petIds) {
                petIdList.add(new HashMap<String, Object>() {{
                    put("petUserPetId", petId);
                }});
            }
            param.put("petIds", petIdList);
        }
        return addModel("pet.account", param);
    }

    public List<Map> getUserAccountAll(Integer userId, Integer year, Integer month) {
        log.info("getUserAccount year:{},month:{}",
                year, month);
        Date date = DateTimeUtils.parseDate("yyyy-MM", year + "-" + month);
        Date maxMonthDate = DateTimeUtils.getMaxMonthDate(date);
        Date minMonthDate = DateTimeUtils.getMinMonthDate(date);
        Condition condition = Condition.betweenCondition("accountDate",
                "\"" + DateTimeUtils.getDateFormat(minMonthDate) + "\"",
                "\"" + DateTimeUtils.getDateFormat(maxMonthDate) + "\"");
        condition = condition.andEqualCondition("userId", userId);
        String reversePolishNotation = condition.getReversePolishNotation();
        return getAllModel("pet.account",
                "id,name,amount,remark,accountDate,petIds.id,petIds.id,petIds.petUserPetId.avatar,petIds.petUserPetId.name",
                reversePolishNotation,
                "accountDate desc");
    }

    public List<Map> getUserAccountList(Integer userId,
                                        Integer pageNum,
                                        Integer pageSize,
                                        String accountBeginDate,
                                        String accountEndDate
    ) {
        return null;
    }


    public List<Map> getUserRemindItem(Integer userId) {
        return getAllModel("pet.remind.item",
                "id,name", null, null);
    }

    public List<Map> getUserAccountItem(Integer userId) {
        return getAllModel("pet.account.item",
                "id,name", null, null);
    }

    public Map getSumAccount(Integer userId, Integer year, Integer month) {
        log.info("getSumAccount userId:{},year:{},month:{}",
                userId, year, month);
        Map param = new HashMap<String, Object>();
        param.put("userId", userId);
        if (ObjectUtils.isNotNull(year)) {
            param.put("year", year);
        }
        if (ObjectUtils.isNotNull(month)) {
            param.put("month", month);
        }

        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("token", shopContext.getBackToken());
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> responseEntity = RestTemplateUtils.post(shopConfig.getServer()
                        + "/pet/get/account/sum",
                headers, param, String.class);
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            return JacksonUtil.convert2Object(responseEntity.getBody(),
                    new TypeReference<Map>() {
                    });
        } else {
            log.error("getSumAccount 错误:" + responseEntity.getBody());
            throw new AvalonException(responseEntity.getBody());
        }
    }
}
